package com.ldn.server.boot3.starter;

import cn.dev33.satoken.exception.NotLoginException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ldn.common.basic.dispose.exception.AppException;
import com.ldn.common.basic.dispose.exception.LoginException;
import com.ldn.common.basic.dispose.vo.ResultDataVo;
import com.ldn.common.basic.enums.system.ReturnCodeEnums;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.UnexpectedTypeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.servlet.resource.NoResourceFoundException;

/**
 * 全局数据返回处理类及异常处理类
 *
 * @author 李大牛家的牛 (scafel@163.com)
 * @product serverless
 * @className MyResponseAdvice
 * @createDate 2025/1/14 - 13:20
 * @description 全局数据返回处理类
 **/
@Slf4j
@RestControllerAdvice
public class ServerResponseAdvice implements ResponseBodyAdvice<Object> {

    private final ObjectMapper objectMapper;

    public ServerResponseAdvice(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }


    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof String) {
            try {
                return objectMapper.writeValueAsString(ResultDataVo.success(body));
            } catch (JsonProcessingException ex) {
                return ResultDataVo.fail(ReturnCodeEnums.RC500.getCode(), ReturnCodeEnums.RC500.getMessage());
            }
        } else if (body instanceof ResultDataVo) {
            return body;
        } else {
            return ResultDataVo.success(body);
        }
    }


    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(AppException.class)
    @ResponseBody
    public ResultDataVo<Object> appException(AppException ex) {
        log.error("appException: { }", ex);
        return ResultDataVo.fail(ex.getCode(), ex.getMessage());
    }

    @ExceptionHandler({LoginException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResultDataVo<Object> loginException(LoginException ex) {
        log.error("loginException:code =>{} ex =>{}", ex.getCode(), ex.getMessage());
        return ResultDataVo.fail(ReturnCodeEnums.RC201.getCode(), ex.getMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public ResultDataVo<Object> methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("methodArgumentNotValidException: { }", ex);
        return ResultDataVo.fail(ReturnCodeEnums.RC203.getCode(), ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseBody
    public ResultDataVo<Object> httpMessageNotReadableException(HttpMessageNotReadableException ex) {
        log.error("httpMessageNotReadableException: { }", ex);
        return ResultDataVo.fail(ReturnCodeEnums.RC203.getCode(), ReturnCodeEnums.RC203.getMessage());
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({UnexpectedTypeException.class, ConstraintViolationException.class, NoResourceFoundException.class})
    @ResponseBody
    public ResultDataVo<Object> otherException(Exception ex) {
        log.error("otherException: { }", ex);
        return ResultDataVo.fail(ReturnCodeEnums.RC400.getCode(), ReturnCodeEnums.RC400.getMessage());
    }

    @ExceptionHandler(NotLoginException.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResultDataVo<Object> notLoginException(NotLoginException ex) {
        log.error("notLoginException: ex =>{}", ex.getMessage());
        return ResultDataVo.fail(ReturnCodeEnums.RC201.getCode(), "未登录，请先登录!");
    }


    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResultDataVo<Object> exception(Exception ex) {
        log.error("exception: { }", ex);
        return ResultDataVo.fail(ReturnCodeEnums.RC500.getCode(), ReturnCodeEnums.RC500.getMessage() );
    }
}
